﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.DirectoryServices.ActiveDirectory;
using System.IO;
using System.Linq;
using System.Reflection.Metadata;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media;
using System.Xml.Linq;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;

namespace ImageTools
{
    internal class JpegGenTool
    {
        private int YuvMode { get; set; }

        private int IsDitherRgb565 { get; set; }

        private String OutFilesPath { get; set; }

        public String Error { get; set; } = "";

        public JpegGenTool(String outFilesPath, int yuvMode, int ditherMode) 
        {
            YuvMode = yuvMode;
            OutFilesPath = outFilesPath;
            if (ditherMode == 0)
            {
                IsDitherRgb565 = 0;
            }
            else if (ditherMode == 1)
            {
                IsDitherRgb565 = 1;
            }
        }

        public int JpegGenFileList(String[] inFilesPath, ref String errStr)
        {
            int ret;

            errStr = "";

            foreach (String inFile in inFilesPath)
            {
                ret = JpegGenOneFile(inFile);
                if (ret != 0)
                {
                    errStr += Error + "\n";
                }
            }

            return 0;
        }

        public int JpegLoadFileToRGB(String inFile, ref int width, ref int height, ref byte[] rgbBytes, ref int rgbFormat)
        {
            byte[] rgbBytes_t;

            using (Image<Rgb24> image = Image.Load<Rgb24>(inFile))
            {
                width = image.Width; 
                height = image.Height;
                rgbBytes_t = new byte[width * height * 3];

                image.ProcessPixelRows(accessor =>
                {
                    for (int y=0; y < image.Height; y++)
                    {
                        Span<Rgb24> pixelRow = accessor.GetRowSpan(y);
                        for(int x = 0; x < image.Width; x++)
                        {
                            int index = (y * image.Width + x) * 3;
                            Rgb24 pixel = pixelRow[x];
                            rgbBytes_t[index] = pixel.B;
                            rgbBytes_t[index + 1] = pixel.G;
                            rgbBytes_t[index + 2] = pixel.R;
                        }
                    }
                });
            }

            rgbBytes = rgbBytes_t;

            return 0;
        }

        /**
         图片Load到内存中,且将RGB888格式Dither到RGB565，即将RGB888的低位变成0
         */
        public int JpegLoadFileToRGBWithDither(String inFile, ref int width, ref int height, ref byte[] rgbBytes, ref int rgbFormat)
        {
            byte[] rgbBytes_t;

            using (Image<Rgb24> image = Image.Load<Rgb24>(inFile))
            {
                width = image.Width;
                height = image.Height;
                rgbBytes_t = new byte[width * height * 3];

                image.ProcessPixelRows(accessor =>
                {
                    for (int y = 0; y < image.Height; y++)
                    {
                        Span<Rgb24> pixelRow = accessor.GetRowSpan(y);
                        for (int x = 0; x < image.Width; x++)
                        {
                            int index = (y * image.Width + x) * 3;
                            Rgb24 pixel = pixelRow[x];
                            rgbBytes_t[index] = pixel.B;
                            rgbBytes_t[index + 1] = pixel.G;
                            rgbBytes_t[index + 2] = pixel.R;

                            rgbBytes_t[index] = DitherRGB565.DitherXY_B(x, y, rgbBytes_t[index + 2]); // B 
                            rgbBytes_t[index + 1] = DitherRGB565.DitherXY_G(x, y, rgbBytes_t[index + 1]); // G
                            rgbBytes_t[index + 2] = DitherRGB565.DitherXY_R(x, y, rgbBytes_t[index]); // R

                            rgbBytes_t[index] &= 0xF8;
                            rgbBytes_t[index + 1] &= 0xFC;
                            rgbBytes_t[index + 2] &= 0xF8;
                        }
                    }
                });
            }

            rgbBytes = rgbBytes_t;

            return 0;
        }

        public int JpegSaveRgbToJpeg(String outFile, int width, int height, int yuvMode, byte[] rgbBytes, int rgbFormat)
        {
            byte[] jpegBytes = Turbojpeg.JpegGenJpegFromRGB888(rgbBytes, width, height, yuvMode);

            File.WriteAllBytes(outFile, jpegBytes);

            return 0;
        }

        public int JpegGenOneFile(String inFile)
        {
            int width = 0;
            int height = 0;
            byte[]? rgbBytes = null;
            int rgbFormat = 0;
            int ret = 0;

            if (IsDitherRgb565 == 0)
            {
                ret = JpegLoadFileToRGB(inFile, ref width, ref height, ref rgbBytes, ref rgbFormat);
            }
            else if (IsDitherRgb565 == 1)
            {
                ret = JpegLoadFileToRGBWithDither(inFile, ref width, ref height, ref rgbBytes, ref rgbFormat);
            }

            if (ret != 0)
            {
                return -1;
            }

            if (YuvMode > 2)
            {
                Error = "Yuv mode Error";
                return -1;
            }

            string outfileName = Path.GetFileNameWithoutExtension(inFile);
            if (YuvMode == 0)
            {
                outfileName += ".jpg";
            }
            else if (YuvMode == 1)
            {
                outfileName += ".jpg";
            }
            else if (YuvMode == 2)
            {
                outfileName += ".jpg";
            }
            
            outfileName = Path.Combine(OutFilesPath, outfileName);

            ret = JpegSaveRgbToJpeg(outfileName, width, height, YuvMode, rgbBytes, rgbFormat);
            if (ret != 0)
            {
                return -1;
            }

            return 0;
        }

    }
}
